<template>
    <div class="app-card">
        <el-card class="el-card-style">
            <div style="display: flex; align-items: center; width: 100%;">
                <span>结构类型：</span>
                <el-select
                    v-model="layout"
                    placeholder="Select"
                    style="width: 160px;"
                    @change="changeLayout(layout)"
                >
                    <el-option
                        v-for="item in layoutOptions"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                    />
                </el-select>
                <el-button
                    type="primary"
                    :icon="Download"
                    style="margin-left: 20px;"
                    @click="downloadXmind"
                >
                    导出（.xmind）
                </el-button>
                <el-upload
                    ref="uploadRef"
                    action="#"
                    :auto-upload="true"
                    :show-file-list="false"
                    accept=".xmind"
                    style="margin-left: 20px;"
                    :http-request="uploadXmind"
                >
                    <template #trigger>
                        <el-button
                            type="primary"
                            :icon="Upload"
                        >
                            导入（.xmind）
                        </el-button>
                    </template>
                </el-upload>
                <el-button
                    type="primary"
                    :icon="Download"
                    style="margin-left: 20px;"
                    @click="downloadExcel"
                >
                    导出（.xlsx）
                </el-button>
                <el-upload
                    ref="uploadRef"
                    action="#"
                    :auto-upload="true"
                    :show-file-list="false"
                    accept=".xlsx"
                    style="margin-left: 20px;"
                    :http-request="uploadXlsx"
                >
                    <template #trigger>
                        <el-button
                            type="primary"
                            :icon="Upload"
                        >
                            导入（.xlsx）
                        </el-button>
                    </template>
                </el-upload>
                <el-button
                    type="success"
                    :icon="Check"
                    style="margin-left: 20px;"
                    @click="save"
                >
                    保存
                </el-button>
                <el-button
                    type="success"
                    :icon="Aim"
                    style="margin-left: 20px;"
                    @click="recovery"
                >
                    初始化
                </el-button>
            </div>
            <div id="mindMapContainer" style="width: 100%; height: calc(100vh - 180px); margin: 0; padding: 0; border-radius: 10px;"></div>
        </el-card>
    </div>
</template>

<script setup>
    import { ref, onMounted, computed } from 'vue'
    import {
        Download,
        Upload,
        Check,
        Aim
    } from '@element-plus/icons-vue'

    import * as XLSX from 'xlsx'
    import { read, utils } from 'xlsx'
    import { ElMessage } from 'element-plus'

    import MindMap from 'simple-mind-map'
    import xmind from 'simple-mind-map/src/parse/xmind.js'
    import ExportXMind from 'simple-mind-map/src/plugins/ExportXMind.js'
    import Export from 'simple-mind-map/src/plugins/Export.js'
    import Select from 'simple-mind-map/src/plugins/Select.js'
    import Drag from 'simple-mind-map/src/plugins/Drag.js'
    import KeyboardNavigation from 'simple-mind-map/src/plugins/KeyboardNavigation.js'
    import Search from 'simple-mind-map/src/plugins/Search.js'
    import Painter from 'simple-mind-map/src/plugins/Painter.js'

    // 注册插件
    MindMap.usePlugin(ExportXMind)
    .usePlugin(Export)
    .usePlugin(Select)
    .usePlugin(Drag)
    .usePlugin(KeyboardNavigation)
    .usePlugin(Search)
    .usePlugin(Painter)

    // 变量
    let mindMap = ref(null)
    let mindData = ref({
        data: {
            text: '父节点'
        },
        children: [
            // {
            //     data: {
            //         text: '子节点1'
            //     },
            //     children: []
            // },
            // {
            //     data: {
            //         text: '子节点2'
            //     },
            //     children: []
            // }
        ]
    })
    let layout = ref('organizationStructure')
    let layoutOptions = [
        {
            label: '组织结构图',
            value: 'organizationStructure'
        },
        {
            label: '逻辑结构图',
            value: 'logicalStructure'
        },
        {
            label: '思维导图',
            value: 'mindMap'
        },
        {
            label: '目录组织图',
            value: 'catalogOrganization'
        },
        {
            label: '时间轴',
            value: 'timeline'
        },
        {
            label: '时间轴2',
            value: 'timeline2'
        },
        {
            label: '鱼骨图',
            value: 'fishbone'
        },
        {
            label: '竖向时间轴',
            value: 'verticalTimeline'
        }
    ]

    // 计算属性
    const fileName = computed(() => {
        let reValue = ''
        switch (layout.value) {
            case 'organizationStructure':
                reValue = '组织结构图'
                break
            case 'logicalStructure':
                reValue = '逻辑结构图'
                break
            case 'mindMap':
                reValue = '思维导图'
                break
            case 'catalogOrganization':
                reValue = '目录结构图'
                break
            case 'timeline':
                reValue = '时间轴'
                break
            case 'timeline2':
                reValue = '时间轴2'
                break
            case 'fishbone':
                reValue = '鱼骨图'
                break
            case 'verticalTimeline':
                reValue = '竖向时间轴'
                break
            default:
                reValue = '文件'
                break
        }
        return reValue
    })

    onMounted( async () => {
        init()
    })

    async function init() {
        mindMap = new MindMap({
            el: document.getElementById('mindMapContainer'),
            data: localStorage.getItem('mindMap') ? JSON.parse(localStorage.getItem('mindMap')) : mindData.value,
            layout: layout.value
        })
        mindMap.setThemeConfig({
            backgroundColor: '#f6f6f7'
        })
    }

    function changeLayout(layout) {
        mindMap.setLayout(layout)
    }

    function downloadXmind() {
        mindMap.export('xmind', true, fileName.value, true)
    }

    async function uploadXmind(file) {
        let data = await xmind.parseXmindFile(file.file)
        mindMap.setData(data)
    }

    function downloadExcel() {
        let updateMindData = mindMap.getData(false)
        const ws = XLSX.utils.aoa_to_sheet(parseTreeToArr(updateMindData))       // 将数据转换为工作表
        const wb = XLSX.utils.book_new()               // 创建工作簿
        XLSX.utils.book_append_sheet(wb, ws, "sheet1") // 添加工作表
        XLSX.writeFile(wb, `${fileName.value}.xlsx`)
    }

    async function uploadXlsx(file) {
        const wb = read(await fileToBuffer(file.file))
        const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {
            header: 1
        })
        mindMap.setData(arr2Tree(data)[0])
    }

    function fileToBuffer(file) {
        return new Promise(r => {
            const reader = new FileReader()
            reader.onload = () => {
                r(reader.result)
            }
            reader.readAsArrayBuffer(file)
        })
    }

    function arr2List(arr) {
        const list = []
        const head = {
            data: {
                text: arr[0]
            },
            children: []
        }
        let prev = head
        list.push(prev)
        for (let i = 1; i < arr.length; i++) {
            const current = {
                data: {
                    text: arr[i]
                },
                children: []
            };
            prev.children.push(current)
            prev = current
        }
        return list
    }

    function mergeList(tree, list) {
        if (!tree) {
            return
        }
        const hasCommonParent = tree.some(treeItem => {
            // 有共同的父节点
            if (treeItem.data && list[0] && treeItem.data.text && list[0].data.text && treeItem.data.text === list[0].data.text) {
                mergeList(treeItem.children, list[0].children)
                return true
            }
            return false
        })

        if (!tree.length || !hasCommonParent) {
            if (list[0]) {
                tree.push(list[0])
            }
        }
    }

    function arr2Tree(arr) {
        const tree = []
        arr.forEach((item) => {
            const list = arr2List(item)
            mergeList(tree, list)
        });
        return tree
    }

    // 树结构转化为二维数组
    function parseTreeToArr(root) {
        const result = []
        const dfs = (node, path = []) => {
            path.push(node.data.text)
            if (node.children.length === 0) {
                result.push([...path])
            } else {
                node.children.forEach(child => dfs(child, [...path]))
            }
        }
        dfs(root)
        return result
    }

    function save() {
        localStorage.setItem('mindMap', JSON.stringify(mindMap.getData(false)))
        ElMessage({
            type: 'success',
            message: '保存成功！'
        })
    }

    function recovery() {
        localStorage.removeItem('mindMap')
        mindMap.setData(mindData.value)
        ElMessage({
            type: 'success',
            message: '已初始化！'
        })
    }
</script>

<style scoped>
.app-card {
    width: 100%;
    height: calc(100vh - 95px);
    padding: 5px;
}

.el-card-style {
    width: 100%;
    height: 100%;
    overflow: auto;
}
</style>
